# - Find MS Visual C++
#
#  VC_INCLUDE_DIR  - where to find headers
#  VC_INCLUDE_DIRS - where to find headers
#  VC_LIBRARY_DIR  - where to find libraries
#  VC_FOUND        - True if MSVC found.

MACRO(ADD_TRAILING_SLASH _FILENAME_VAR)
  # put content in a new variable
  SET(_FILENAME ${${_FILENAME_VAR}})
  # get length of the string
  STRING(LENGTH ${_FILENAME} _LEN)
  # convert length to last pos
  MATH(EXPR _POS "${_LEN}-1")
  # get last character of the string
  STRING(SUBSTRING ${_FILENAME} ${_POS} 1 _FILENAME_END)
  # compare it with a slash
  IF(NOT _FILENAME_END STREQUAL "/")
    # not a slash, append it
    SET(${_FILENAME_VAR} "${_FILENAME}/")
  ELSE()
    # already a slash
  ENDIF()
ENDMACRO()

MACRO(DETECT_VC_VERSION_HELPER _ROOT _VERSION)
  # Software/Wow6432Node/...
  GET_FILENAME_COMPONENT(VC${_VERSION}_DIR "[${_ROOT}\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7;${_VERSION}]" ABSOLUTE)

  IF(VC${_VERSION}_DIR AND VC${_VERSION}_DIR STREQUAL "/registry")
    SET(VC${_VERSION}_DIR)
    GET_FILENAME_COMPONENT(VC${_VERSION}_DIR "[${_ROOT}\\SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7;${_VERSION}]" ABSOLUTE)

    IF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry")
      # be sure it's finishing by a /
      ADD_TRAILING_SLASH(VC${_VERSION}_DIR)

      SET(VC${_VERSION}_DIR "${VC${_VERSION}_DIR}VC/")
    ENDIF()
  ENDIF()

  IF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry")
    SET(VC${_VERSION}_FOUND ON)
    DETECT_EXPRESS_VERSION(${_VERSION})
    IF(NOT MSVC_FIND_QUIETLY)
      SET(_VERSION_STR ${_VERSION})
      IF(MSVC_EXPRESS)
        SET(_VERSION_STR "${_VERSION_STR} Express")
      ENDIF()
      MESSAGE(STATUS "Found Visual C++ ${_VERSION_STR} in ${VC${_VERSION}_DIR}")
    ENDIF()
  ELSEIF(VC${_VERSION}_DIR AND NOT VC${_VERSION}_DIR STREQUAL "/registry")
    SET(VC${_VERSION}_FOUND OFF)
    SET(VC${_VERSION}_DIR "")
  ENDIF()
ENDMACRO()

MACRO(DETECT_VC_VERSION _VERSION)
  IF(NOT VC_FOUND)
    SET(VC${_VERSION}_FOUND OFF)
    DETECT_VC_VERSION_HELPER("HKEY_CURRENT_USER" ${_VERSION})

    IF(NOT VC${_VERSION}_FOUND)
      DETECT_VC_VERSION_HELPER("HKEY_LOCAL_MACHINE" ${_VERSION})
    ENDIF()

    IF(VC${_VERSION}_FOUND)
      SET(VC_FOUND ON)
      SET(VC_DIR "${VC${_VERSION}_DIR}")
    ENDIF()
  ENDIF()
ENDMACRO()

MACRO(DETECT_EXPRESS_VERSION _VERSION)
  GET_FILENAME_COMPONENT(MSVC_EXPRESS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VCExpress\\${_VERSION}\\Setup\\VC;ProductDir]" ABSOLUTE)

  IF(MSVC_EXPRESS AND NOT MSVC_EXPRESS STREQUAL "/registry")
    SET(MSVC_EXPRESS ON)
  ENDIF()
ENDMACRO()

IF(MSVC_VERSION GREATER 1909)
  DETECT_VC_VERSION("15.0")
  SET(MSVC_TOOLSET "140")

  SET(VC_DIR "${VC_DIR}Tools/MSVC")

  FILE(GLOB MSVC_TOOLCHAIN_VERSIONS RELATIVE ${VC_DIR} "${VC_DIR}/*")

  IF(MSVC_TOOLCHAIN_VERSIONS)
    LIST(SORT MSVC_TOOLCHAIN_VERSIONS)
    LIST(REVERSE MSVC_TOOLCHAIN_VERSIONS)
  ENDIF()

  IF(NOT MSVC_TOOLCHAIN_VERSIONS)
    MESSAGE(FATAL_ERROR "No MSVC version found in default search path ${VC_DIR}")
  ENDIF()

  LIST(GET MSVC_TOOLCHAIN_VERSIONS 0 MSVC_TOOLCHAIN_VERSION)

  SET(VC_DIR "${VC_DIR}/${MSVC_TOOLCHAIN_VERSION}")
  SET(VC_INCLUDE_DIR "${VC_DIR}/include")
ELSEIF(MSVC14)
  DETECT_VC_VERSION("14.0")
  SET(MSVC_TOOLSET "140")
ELSEIF(MSVC12)
  DETECT_VC_VERSION("12.0")
  SET(MSVC_TOOLSET "120")
ELSEIF(MSVC11)
  DETECT_VC_VERSION("11.0")
  SET(MSVC_TOOLSET "110")
ELSEIF(MSVC10)
  DETECT_VC_VERSION("10.0")
  SET(MSVC_TOOLSET "100")
ELSEIF(MSVC90)
  DETECT_VC_VERSION("9.0")
  SET(MSVC_TOOLSET "90")
ELSEIF(MSVC80)
  DETECT_VC_VERSION("8.0")
  SET(MSVC_TOOLSET "80")
ENDIF()

# If you plan to use VC++ compilers with WINE, set VC_DIR environment variable
IF(NOT VC_DIR)
  SET(VC_DIR $ENV{VC_DIR})
  # Fix path
  FILE(TO_CMAKE_PATH ${VC_DIR} VC_DIR)
ENDIF()

IF(NOT VC_DIR)
  IF(CMAKE_CXX_COMPILER)
    SET(_COMPILER ${CMAKE_CXX_COMPILER})
  ELSE()
    SET(_COMPILER ${CMAKE_C_COMPILER})
  ENDIF()
  STRING(REGEX REPLACE "/(bin|BIN|Bin)/.+" "" VC_DIR ${_COMPILER})
ENDIF()

IF(NOT VC_INCLUDE_DIR AND VC_DIR AND EXISTS "${VC_DIR}")
  SET(VC_INCLUDE_DIR "${VC_DIR}/include")
  IF(EXISTS "${VC_INCLUDE_DIR}")
    SET(VC_FOUND ON)
  ENDIF()
ENDIF()

SET(MSVC_REDIST_DIR "${EXTERNAL_PATH}/redist")

IF(NOT EXISTS "${MSVC_REDIST_DIR}")
  SET(MSVC_REDIST_DIR "${VC_DIR}/redist")
  
  IF(NOT EXISTS "${MSVC_REDIST_DIR}")
    SET(MSVC_REDIST_DIR)
  ENDIF()
ENDIF()

IF(MSVC_REDIST_DIR)
  IF(MSVC1411 OR MSVC1410)
    # If you have VC++ 2017 Express, put x64/Microsoft.VC141.CRT/*.dll in ${EXTERNAL_PATH}/redist
    # original files whould be in ${VC_DIR}/Redist/MSVC/14.11.25325/x64/Microsoft.VC141.CRT
    SET(MSVC14_REDIST_DIR "${MSVC_REDIST_DIR}")
  ELSEIF(MSVC14)
    SET(MSVC14_REDIST_DIR "${MSVC_REDIST_DIR}")
  ELSEIF(MSVC12)
    # If you have VC++ 2013 Express, put x64/Microsoft.VC120.CRT/*.dll in ${EXTERNAL_PATH}/redist
    SET(MSVC12_REDIST_DIR "${MSVC_REDIST_DIR}")
  ELSEIF(MSVC11)
    # If you have VC++ 2012 Express, put x64/Microsoft.VC110.CRT/*.dll in ${EXTERNAL_PATH}/redist
    SET(MSVC11_REDIST_DIR "${MSVC_REDIST_DIR}")
  ELSEIF(MSVC10)
      # If you have VC++ 2010 Express, put x64/Microsoft.VC100.CRT/*.dll in ${EXTERNAL_PATH}/redist
    SET(MSVC10_REDIST_DIR "${MSVC_REDIST_DIR}")
  ELSEIF(MSVC90)
    SET(MSVC90_REDIST_DIR "${MSVC_REDIST_DIR}")
  ELSEIF(MSVC80)
    SET(MSVC80_REDIST_DIR "${MSVC_REDIST_DIR}")
  ENDIF()
ENDIF()

MESSAGE(STATUS "Using headers from ${VC_INCLUDE_DIR}")

SET(VC_INCLUDE_DIRS ${VC_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${VC_INCLUDE_DIR})
